﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;

namespace 五味子串口调试助手3
{
    public class MainWindowModel : NotifyPropertyChanged
    {
        private string _Title;
        public string Title { get { return _Title; } set { SetProperty(ref  _Title, value); } }

        private static IEnumerable<object> _checkArr = from t in tools.GetChildTypes(typeof(checkBase)) select Activator.CreateInstance(t);
        public IEnumerable<object> checkArr
        {
            get { return _checkArr; }
        }
        public string[] commPortArr
        {
            get { return System.IO.Ports.SerialPort.GetPortNames(); }
        }

        public string[] bandRateArr
        {
            get { return new string[] { "1200", "2400", "4800", "9600", "14400", "19200", "38400", "56000", "57600", "115200", "194000" }; }
        }

        public string[] dataBitsArr
        {
            get { return new string[] { "5", "6", "7", "8" }; }
        }

        public string[] stopBitsArr
        {
            get { return new string[] { "1", "2" }; }
        }

        public string[] verfyBitsArr
        {
            get { return System.Enum.GetNames(typeof(System.IO.Ports.Parity)); }
        }

        private string _commPort;
        public string commPort { get { return _commPort; } set { SetProperty(ref  _commPort, value); } }

        private int _bandRate;
        public int bandRate { get { return _bandRate; } set { SetProperty(ref  _bandRate, value); } }

        private int _dataBits;
        public int dataBits { get { return _dataBits; } set { SetProperty(ref  _dataBits, value); } }

        private string _verfyBits;
        public string verfyBits { get { return _verfyBits; } set { SetProperty(ref  _verfyBits, value); } }

        private int _stopBits;
        public int stopBits { get { return _stopBits; } set { SetProperty(ref  _stopBits, value); } }

        private bool _commIsOpen;
        public bool commIsOpen { get { return _commIsOpen; } set { SetProperty(ref  _commIsOpen, value); } }

        private bool _isSendHex;
        public bool isSendHex { get { return _isSendHex; } set { SetProperty(ref  _isSendHex, value); } }

        private bool _isDisplayHex;
        public bool isDisplayHex { get { return _isDisplayHex; } set { SetProperty(ref  _isDisplayHex, value); } }

        private bool _isDisplayAscii;
        public bool isDisplayAscii { get { return _isDisplayAscii; } set { SetProperty(ref  _isDisplayAscii, value); } }

        private int _sendMessageNum;
        public int sendMessageNum { get { return _sendMessageNum; } set { SetProperty(ref  _sendMessageNum, value); } }

        private int _sendBytesNum;
        public int sendBytesNum { get { return _sendBytesNum; } set { SetProperty(ref  _sendBytesNum, value); } }

        private int _reciveMessageNum;
        public int reciveMessageNum { get { return _reciveMessageNum; } set { SetProperty(ref  _reciveMessageNum, value); } }

        private int _reciveBytesNum;
        public int reciveBytesNum { get { return _reciveBytesNum; } set { SetProperty(ref  _reciveBytesNum, value); } }

        private string _sendText;
        public string sendText { get { return _sendText; } set { SetProperty(ref  _sendText, value); } }

        private string _sendCheckText;
        public string sendCheckText { get { return _sendCheckText; } set { SetProperty(ref  _sendCheckText, value); } }

        private bool _enableClcSend;
        public bool enableClcSend { get { return _enableClcSend; } set { SetProperty(ref  _enableClcSend, value); } }

        private int _clcInterval;
        public int clcInterval { get { return _clcInterval; } set { SetProperty(ref  _clcInterval, value); } }

        private bool _enableConditionSend;
        public bool enableConditionSend { get { return _enableConditionSend; } set { SetProperty(ref  _enableConditionSend, value); } }

        private bool _enableReciveFilter;
        public bool enableReciveFilter { get { return _enableReciveFilter; } set { SetProperty(ref  _enableReciveFilter, value); } }

        private string _filterText;
        public string filterText { get { return _filterText; } set { SetProperty(ref  _filterText, value); } }

        private string _helpFilterString;
        public string helpFilterString { get { return _helpFilterString; } set { SetProperty(ref  _helpFilterString, value); } }
        public Thread th { get; set; }

        public DateTime lastTimeClcSend { get; set; }

        public int clcSendIndex { get; set; }

        public bool stopThread { get; set; }

        public bool isPauseDisplay { get; set; }

        public bool isAutoScroll { get; set; }


        private checkBase _checkMethod = _checkArr.First() as checkBase;
        public checkBase checkMethod { get { return _checkMethod; } set { SetProperty(ref  _checkMethod, value); } }
        public ScrollViewer visualChild { get; set; }

        public ObservableCollection<OneSerialDataClass> list_allData { get; set; }
        public ObservableCollection<clcSendDataClass> list_clcSend { get; set; }
        public ObservableCollection<conditionSendDataClass> list_conditionSend { get; set; }

        public SerialPort serialPort { get; set; }
        public ICommand SendCommand { get; set; }
        public ICommand OpenCommCommand { get; set; }
        public ICommand addClcSendCommand { get; set; }
        public ICommand addConditionSendCommand { get; set; }

        public MainWindow mainWindow { get; set; }

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainWindowModel()
        {
            Title = "五味子串口调试助手3.0    BUG联系Tel：15502019059";
            helpFilterString = @"如：b[0] = 0xEB && b[1] = 0x90 || b[5] = 0x55     为显示所有EB 90开头或第6个字节为0x55的数据。";

            list_allData = new ObservableCollection<OneSerialDataClass>();
            list_clcSend = new ObservableCollection<clcSendDataClass>();
            list_conditionSend = new ObservableCollection<conditionSendDataClass>();

            SendCommand = new SendCommand(this);
            OpenCommCommand = new OpenCommCommand(this);
            addClcSendCommand = new addClcSendCommand(this);
            addConditionSendCommand = new addConditionSendCommand(this);

            lastTimeClcSend = DateTime.Now;

            th = new Thread(reciveThread);
            th.Start();
        }

        private void reciveThread(object obj)
        {
            while (!stopThread)
            {
                if (!commIsOpen)
                {
                    Thread.Sleep(100);
                }
                else
                {
                    byte[] array = new byte[1024];
                    int num = 0;
                    try
                    {
                        int num2;
                        while ((num2 = this.serialPort.Read(array, num, 1024 - num)) != 0)
                        {
                            num += num2;
                        }
                    }
                    catch (Exception ex)
                    {
                        if (ex.Message == "对端口的访问被拒绝。")
                        {
                            commIsOpen = false;
                        }
                    }
                    if (num > 0)
                    {
                        reciveMessageNum++;
                        reciveBytesNum += num;

                        OneSerialDataClass oneData = new OneSerialDataClass(array, num);

                        mainWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new ThreadStart(delegate
                        {
                            list_allData.Add(oneData);
                            reflushDataView();
                        }));

                        // 条件发送
                        if (enableConditionSend)
                        {
                            foreach (var v in list_conditionSend)
                            {
                                if (!v.enable || v.reciveText.Trim() == "" || v.sendText.Trim() == "")
                                {
                                    break;
                                }
                                if (v.reciveText.Trim() == oneData.asciiString.Trim())
                                {
                                    send(new OneSerialDataClass(v.sendText, false));
                                }
                                else if (v.reciveText.ToLower().Trim().Replace(" ", "") == oneData.hexString.ToLower().Trim().Replace(" ", ""))
                                {
                                    send(new OneSerialDataClass(v.sendText, true));
                                }
                            }
                        }
                    }
                    Thread.Sleep(10);

                    // 如开启循环发送
                    if (enableClcSend)
                    {
                        clcInterval = clcInterval < 20 ? 20 : clcInterval;
                        // 如超时
                        if ((DateTime.Now - lastTimeClcSend) > new TimeSpan(0, 0, 0, 0, clcInterval))
                        {
                            lastTimeClcSend = DateTime.Now;
                            clcSendDataClass data = getOneClcSendData();
                            if (data != null)
                            {
                                mainWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new ThreadStart(delegate
                                {
                                    for (int i = 0; i < mainWindow.clcSendDataGrid.Items.Count; ++i)
                                    {
                                        DataGridRow row = mainWindow.clcSendDataGrid.ItemContainerGenerator.ContainerFromIndex(i) as DataGridRow;
                                        if (row != null && row.Item == data)
                                        {
                                            row.Background = new SolidColorBrush(Colors.YellowGreen);
                                        }
                                        else
                                        {
                                            row.Background = new SolidColorBrush(Colors.White);
                                        }
                                    }
                                }));

                                send(new OneSerialDataClass(data.sendText, isSendHex));
                            }
                        }
                    }
                }
            }
        }

        public clcSendDataClass getOneClcSendData()
        {
            int count = list_clcSend.Count;
            if (count == 0)
            {
                return null;
            }
            for (int i = 0; i < count; ++i)
            {
                clcSendDataClass data = list_clcSend[clcSendIndex++ % count];
                if (data.enable && data.sendText != null && data.sendText.Trim() != "")
                {
                    return data;
                }
            }
            return null;
        }

        public void send(OneSerialDataClass oneSerialData)
        {
            byte[] array = tools.hexStringToByte(oneSerialData.hexString);
            if (array.Length == 0)
            {
                return;
            }
            try
            {
                serialPort.Write(array, 0, array.Length);

                sendMessageNum++;
                sendBytesNum += array.Length;
            }
            catch (Exception ex)
            {
                if (ex.Message == "对端口的访问被拒绝。")
                {
                    commIsOpen = false;
                }
                return;
            }

            mainWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new ThreadStart(delegate
            {
                list_allData.Add(oneSerialData);
                reflushDataView();
            }));
        }

        public bool parseFilter(string s, out int index, out byte value)
        {
            index = -1;
            value = 0xFF;
            string[] pair = s.Split('=');
            if (pair.Length != 2)
            {
                return false;
            }

            int startIndex = pair[0].IndexOf('[');
            int endIndex = pair[0].IndexOf(']');
            if (startIndex == -1 || endIndex == -1 || endIndex - startIndex - 1 < 1)
            {
                return false;
            }

            string indexString = pair[0].Substring(startIndex + 1, endIndex - startIndex - 1);
            if (int.TryParse(indexString, out index) == true && pair[1].Length == 4 && pair[1].ToLower().IndexOf("0x") == 0)
            {
                value = tools.hexStringToByte(pair[1].Substring(2, 2))[0];
                return true;
            }
            return false;
        }

        // 满足要求
        public bool isSatisfaction(OneSerialDataClass data, Dictionary<int, byte> dic)
        {
            foreach (var v in dic)
            {
                if (data.bytes.Length > v.Key && data.bytes[v.Key] != v.Value)
                {
                    return false;
                }
            }
            return true;
        }
        public void reflushDataView()
        {
            if (!enableReciveFilter || filterText == null || filterText.Trim() == "")
            {
                if (mainWindow.dataGrid_recive.ItemsSource != list_allData)
                {
                    mainWindow.dataGrid_recive.ItemsSource = list_allData;
                }

                if (!isPauseDisplay)
                {
                    if (visualChild == null)
                    {
                        visualChild = tools.GetVisualChild<ScrollViewer>(mainWindow.dataGrid_recive);
                    }
                    visualChild.ScrollToEnd();
                }
                return;
            }

            List<OneSerialDataClass> list = new List<OneSerialDataClass>();
            string[] s = filterText.Trim().Replace(" ", "").Split(new string[] { "||" }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var ss in s)
            {
                string[] sss = ss.Split(new string[] { "&&" }, StringSplitOptions.RemoveEmptyEntries);
                if (sss.Length == 1)
                {
                    int index = 0;
                    byte value = 0;
                    if (parseFilter(sss[0], out index, out value))
                    {
                        list.AddRange(from c in list_allData where c.bytes.Length > index && c.bytes[index] == value select c);
                    }
                }
                else
                {
                    Dictionary<int, byte> dic = new Dictionary<int, byte>();

                    foreach (var ssss in sss)
                    {
                        int index = 0;
                        byte value = 0;
                        if (parseFilter(ssss, out index, out value))
                        {
                            dic.Add(index, value);
                        }
                    }
                    list.AddRange(from c in list_allData where isSatisfaction(c, dic) select c);
                }
            }
            tools.removeDuplicate(list);
            mainWindow.dataGrid_recive.ItemsSource = list;

            if (!isPauseDisplay)
            {
                if (visualChild == null)
                {
                    visualChild = tools.GetVisualChild<ScrollViewer>(mainWindow.dataGrid_recive);
                }
                visualChild.ScrollToEnd();
            }
        }
    }
}
